Added Xen-API-style error handling for INTERNAL_ERROR and
authorEwan Mellor <ewan@xensource.com>
Fri, 22 Dec 2006 11:39:29 +0000 (11:39 +0000)
committerEwan Mellor <ewan@xensource.com>
Fri, 22 Dec 2006 11:39:29 +0000 (11:39 +0000)
MESSAGE_METHOD_UNKNOWN.  Only add the Xen-API methods to the official Xen-API
XML-RPC server, not to the legacy one.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
tools/python/xen/util/xmlrpclib2.py
tools/python/xen/xend/server/SrvServer.py
tools/python/xen/xend/server/XMLRPCServer.py

index efb29d7b0e54a1bee0cf951b7de175cc32c2f7df..e31b28983930647a6458137ffcbebdc8a184c52c 100644 (file)
@@ -20,6 +20,7 @@
 An enhanced XML-RPC client/server interface for Python.
 """
 
+import re
 import string
 import fcntl
 from types import *
@@ -163,8 +164,10 @@ class ServerProxy(xmlrpclib.ServerProxy):
 class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
     allow_reuse_address = True
 
-    def __init__(self, addr, allowed, requestHandler=None,
+    def __init__(self, addr, allowed, xenapi, requestHandler=None,
                  logRequests = 1):
+        self.xenapi = xenapi
+        
         if requestHandler is None:
             requestHandler = XMLRPCRequestHandler
         SimpleXMLRPCServer.__init__(self, addr,
@@ -182,7 +185,7 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
         flags |= fcntl.FD_CLOEXEC
         fcntl.fcntl(client.fileno(), fcntl.F_SETFD, flags)
         return (client, addr)
-                                                                                
+
     def _marshaled_dispatch(self, data, dispatch_method = None):
         params, method = xmlrpclib.loads(data)
         if False:
@@ -214,13 +217,30 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
         except xmlrpclib.Fault, fault:
             response = xmlrpclib.dumps(fault)
         except Exception, exn:
-            import xen.xend.XendClient
-            log.exception(exn)
-            response = xmlrpclib.dumps(
-                xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
-
+            if self.xenapi:
+                if _is_not_supported(exn):
+                    errdesc = ['MESSAGE_METHOD_UNKNOWN', method]
+                else:
+                    log.exception('Internal error handling %s', method)
+                    errdesc = ['INTERNAL_ERROR', str(exn)]
+                response = xmlrpclib.dumps(
+                    ({ "Status": "Failure",
+                       "ErrorDescription": errdesc },),
+                    methodresponse = 1)
+            else:
+                log.exception('Internal error handling %s', method)
+                import xen.xend.XendClient
+                response = xmlrpclib.dumps(
+                    xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
         return response
 
+
+notSupportedRE = re.compile(r'method "(.*)" is not supported')
+def _is_not_supported(exn):
+    m = notSupportedRE.search(exn[0])
+    return m is not None
+
+
 # This is a XML-RPC server that sits on a Unix domain socket.
 # It implements proper support for allow_reuse_address by
 # unlink()'ing an existing socket.
@@ -235,10 +255,10 @@ class UnixXMLRPCRequestHandler(XMLRPCRequestHandler):
 class UnixXMLRPCServer(TCPXMLRPCServer):
     address_family = socket.AF_UNIX
 
-    def __init__(self, addr, allowed, logRequests = 1):
+    def __init__(self, addr, allowed, xenapi, logRequests = 1):
         mkdir.parents(os.path.dirname(addr), stat.S_IRWXU, True)
         if self.allow_reuse_address and os.path.exists(addr):
             os.unlink(addr)
 
-        TCPXMLRPCServer.__init__(self, addr, allowed,
+        TCPXMLRPCServer.__init__(self, addr, allowed, xenapi,
                                  UnixXMLRPCRequestHandler, logRequests)
index 4dfe8584e0edb9909588aa2fad91981bb9bcc75a..b5406547fcc832b390787a9cd167986e60623bf2 100644 (file)
@@ -198,16 +198,18 @@ def _loadConfig(servers, root, reload):
 
                 if len(addrport) == 1:
                     if addrport[0] == 'unix':
-                        servers.add(XMLRPCServer(auth,
+                        servers.add(XMLRPCServer(auth, True,
                                                  path = XEN_API_SOCKET,
                                                  hosts_allowed = allowed))
                     else:
                         servers.add(
-                            XMLRPCServer(auth, True, '', int(addrport[0]),
+                            XMLRPCServer(auth, True, True, '',
+                                         int(addrport[0]),
                                          hosts_allowed = allowed))
                 else:
                     addr, port = addrport
-                    servers.add(XMLRPCServer(auth, True, addr, int(port),
+                    servers.add(XMLRPCServer(auth, True, True, addr,
+                                             int(port),
                                              hosts_allowed = allowed))
         except ValueError, exn:
             log.error('Xen-API server configuration %s is invalid.', api_cfg)
@@ -215,10 +217,10 @@ def _loadConfig(servers, root, reload):
             log.error('Xen-API server configuration %s is invalid.', api_cfg)
 
     if xroot.get_xend_tcp_xmlrpc_server():
-        servers.add(XMLRPCServer(XendAPI.AUTH_PAM, True))
+        servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, True))
 
     if xroot.get_xend_unix_xmlrpc_server():
-        servers.add(XMLRPCServer(XendAPI.AUTH_PAM))
+        servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False))
 
 
 def create():
index c29b4b6bdd168698b21bf93a9b0d26034a97db71..05646fcea6946fd1b57c0b4efc0511f3105b0fcd 100644 (file)
@@ -89,8 +89,8 @@ methods = ['device_create', 'device_configure',
 exclude = ['domain_create', 'domain_restore']
 
 class XMLRPCServer:
-    def __init__(self, auth, use_tcp=False, host = "localhost", port = 8006,
-                 path = XML_RPC_SOCKET, hosts_allowed = None):
+    def __init__(self, auth, use_xenapi, use_tcp=False, host = "localhost",
+                 port = 8006, path = XML_RPC_SOCKET, hosts_allowed = None):
         self.use_tcp = use_tcp
         self.port = port
         self.host = host
@@ -100,7 +100,7 @@ class XMLRPCServer:
         self.ready = False        
         self.running = True
         self.auth = auth
-        self.xenapi = XendAPI.XendAPI(auth)
+        self.xenapi = use_xenapi and XendAPI.XendAPI(auth) or None
         
     def run(self):
         authmsg = (self.auth == XendAPI.AUTH_NONE and 
@@ -115,11 +115,13 @@ class XMLRPCServer:
                          self.port, authmsg)
                 self.server = TCPXMLRPCServer((self.host, self.port),
                                               self.hosts_allowed,
+                                              self.xenapi is not None,
                                               logRequests = False)
             else:
                 log.info("Opening Unix domain socket XML-RPC server on %s%s",
                          self.path, authmsg)
                 self.server = UnixXMLRPCServer(self.path, self.hosts_allowed,
+                                               self.xenapi is not None,
                                                logRequests = False)
         except socket.error, exn:
             log.error('Cannot start server: %s!', exn.args[1])
@@ -133,9 +135,10 @@ class XMLRPCServer:
         # and has the 'api' attribute.
         
         for meth_name in dir(self.xenapi):
-            meth = getattr(self.xenapi, meth_name)
-            if meth_name[0] != '_' and callable(meth) and hasattr(meth, 'api'):
-                self.server.register_function(meth, getattr(meth, 'api'))
+            if meth_name[0] != '_':
+                meth = getattr(self.xenapi, meth_name)
+                if callable(meth) and hasattr(meth, 'api'):
+                    self.server.register_function(meth, getattr(meth, 'api'))
                 
         # Legacy deprecated xm xmlrpc api
         # --------------------------------------------------------------------